{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "name": "NeutralAtom.ipynb",
      "provenance": [],
      "collapsed_sections": [],
      "include_colab_link": true
    },
    "kernelspec": {
      "name": "python3",
      "display_name": "Python 3"
    }
  },
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "view-in-github",
        "colab_type": "text"
      },
      "source": [
        "<a href=\"https://colab.research.google.com/github/JackHidary/quantumcomputingbook/blob/master/Notes/NeutralAtom.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "bNlUyYQcgMF-",
        "colab_type": "text"
      },
      "source": [
        "# **Neutral Atom Device Class**\n",
        "This notebook provides an introductiong to making circuits that are compatable with neutral atom devices in Cirq. The NeutralAtomDevice class is available starting with release 0.5.0."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "gJBgV_Wlo0TP",
        "colab_type": "text"
      },
      "source": [
        ""
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "GTjMbjyAfJCK",
        "colab_type": "code",
        "outputId": "04ca899f-1b0d-40be-b069-d900cda35231",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 105
        }
      },
      "source": [
        "# install release containing NeutralAtomDevice and IonDevice classes\n",
        "!pip install cirq~=0.5.0 --quiet"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "\u001b[K     |████████████████████████████████| 716kB 2.9MB/s \n",
            "\u001b[K     |████████████████████████████████| 12.8MB 11.0MB/s \n",
            "\u001b[31mERROR: plotnine 0.5.1 has requirement matplotlib>=3.0.0, but you'll have matplotlib 2.2.4 which is incompatible.\u001b[0m\n",
            "\u001b[31mERROR: albumentations 0.1.12 has requirement imgaug<0.2.7,>=0.2.5, but you'll have imgaug 0.2.9 which is incompatible.\u001b[0m\n",
            "\u001b[?25h"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "LVV6w_cLzoPS",
        "colab_type": "text"
      },
      "source": [
        ""
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Z0X2AWrhrcHR",
        "colab_type": "text"
      },
      "source": [
        "Let's get some imports out of the way and construct an instance of the NeutralAtomDevice class. We won't worry about the details of the constructor arguments just yet, we just want an instance of the class for demonstration purposes."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "On6Wrh3XhSPO",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "import cirq\n",
        "import numpy as np\n",
        "from matplotlib import pyplot as plt\n",
        "\n",
        "ms = cirq.Duration(nanos=10**6)\n",
        "us = cirq.Duration(nanos=10**3)\n",
        "neutral_device = cirq.NeutralAtomDevice(measurement_duration = 5*ms,\n",
        "                                       gate_duration = 100*us,\n",
        "                                       control_radius = 2,\n",
        "                                       max_parallel_z = 3,\n",
        "                                       max_parallel_xy = 3,\n",
        "                                       max_parallel_c = 3,\n",
        "                                       qubits = [cirq.GridQubit(row, col) \n",
        "                                                 for col in range(3) \n",
        "                                                 for row in range(3)])"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "2dl0K4NF3KH7",
        "colab_type": "text"
      },
      "source": [
        ""
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "v3YMaPw1hfV_",
        "colab_type": "text"
      },
      "source": [
        "## NeutralAtomDevice\n",
        "Disclaimer: As with any proposed architecture for quantum computing, several research groups around the world are working towards a device based on neutral atom qubits. Each research group has a different approach, such as using different atomic species or working with a different number of dimensions of atomic qubit arrays. As such, the NeutralAtomDevice class will not accurately reflect all such devices. The class is based on the two dimensional cesium array at the University of Wisconsin-Madison in the research group of Mark Saffman. Development of this device is being pursued as part of a strategic partnershp between the University of Wisconsin-Madison and ColdQuanta.\n",
        "\n",
        "\n",
        "---\n",
        "\n",
        "### Native Gate Set\n",
        "The gates supported by the NeutralAtomDevice class can be placed in three categories:\n",
        "\n",
        "\n",
        "1.   Single qubit rotations about the Z axis\n",
        "2.   Single qubit rotations about an arbitrary axis in the X-Y plane (I refer to these as XY gates in this tutorial)\n",
        "3.   Controlled gates: CZ, CNOT, CCZ, CCNOT (TOFFOLI)\n",
        "\n",
        "\n",
        "For the single qubit rotations, any rotation angle is fine. However, for the controlled gates, the rotation must be a multiple of $\\pi$ due to the physical implementation of the gates. Cirq supports raising gates to arbitrary exponents. In order to satisfy the restriction of the controlled gate rotation, the exponent of the controlled gate must be an integer.\n",
        "\n",
        "\n",
        "You are allowed to specify the connectivity of the controlled gates via the control_radius argument of the NeutralAtomDevice constructor. This argument specifies the maximum distance between pairs of atoms acted on by a controlled gate. \n",
        "\n",
        "\n",
        "The neutral atom scheme for controlled gates also allows for multiple controls so long as every pair of atoms acted on by the controlled gate are close enough to eachother. The NeutralAtomDevice class does not currently support gates with greater than two controls  but we hope to implement support for them in the near term.\n",
        "\n",
        "\n",
        "---\n",
        "\n",
        "\n",
        "Some examples of gates in Cirq that the device supports are given below."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "Hotk4cHCpXCV",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "# Single Qubit Z rotation by Pi/5 radians\n",
        "neutral_device.validate_gate(cirq.Rz(np.pi/5))\n",
        "# Single Qubit rotation about axis in X-Y plane Pi/3 radians from X axis by angle of Pi/7\n",
        "neutral_device.validate_gate(cirq.PhasedXPowGate(phase_exponent=np.pi/3,exponent=np.pi/7))\n",
        "# Controlled gate with integer exponent \n",
        "neutral_device.validate_gate(cirq.CNOT)\n",
        "# Controlled Not gate with two controls\n",
        "neutral_device.validate_gate(cirq.TOFFOLI)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "nc4zLydMsrkV",
        "colab_type": "text"
      },
      "source": [
        "Some examples of gates in Cirq the device does not support are given below. These code blocks will yield errors describing since the gates are not valid for NeutralAtomDevice."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "ChT4QK7TsabR",
        "colab_type": "code",
        "outputId": "d6adbb1b-ed9f-42b1-9c6b-06008d00134d",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 302
        }
      },
      "source": [
        "#Controlled gate with non-integer exponent (rotation angle must be a multiple of pi)\n",
        "neutral_device.validate_gate(cirq.CZ**1.5)"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "error",
          "ename": "ValueError",
          "evalue": "ignored",
          "traceback": [
            "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
            "\u001b[0;31mValueError\u001b[0m                                Traceback (most recent call last)",
            "\u001b[0;32m<ipython-input-4-5d3cb9a40015>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mneutral_device\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvalidate_gate\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcirq\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mCZ\u001b[0m\u001b[0;34m**\u001b[0m\u001b[0;36m1.5\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
            "\u001b[0;32m/usr/local/lib/python3.6/dist-packages/cirq/neutral_atoms/neutral_atom_devices.py\u001b[0m in \u001b[0;36mvalidate_gate\u001b[0;34m(self, gate)\u001b[0m\n\u001b[1;32m    129\u001b[0m                              ops.CCZPowGate)):\n\u001b[1;32m    130\u001b[0m             \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mgate\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mexponent\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mis_integer\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 131\u001b[0;31m                 \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'controlled gates must have integer exponents'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    132\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    133\u001b[0m     \u001b[0;32mdef\u001b[0m \u001b[0mvalidate_operation\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0moperation\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mops\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mOperation\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;31mValueError\u001b[0m: controlled gates must have integer exponents"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "UPKPh0XMs7zh",
        "colab_type": "code",
        "outputId": "9111daea-5865-4d73-8aff-f061b683c911",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 302
        }
      },
      "source": [
        "# Hadamard gates rotate about the X-Z axis, which isn't compatable with our single qubit rotations\n",
        "neutral_device.validate_gate(cirq.H)"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "error",
          "ename": "ValueError",
          "evalue": "ignored",
          "traceback": [
            "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
            "\u001b[0;31mValueError\u001b[0m                                Traceback (most recent call last)",
            "\u001b[0;32m<ipython-input-5-32e25de2a072>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mneutral_device\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvalidate_gate\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcirq\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mH\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
            "\u001b[0;32m/usr/local/lib/python3.6/dist-packages/cirq/neutral_atoms/neutral_atom_devices.py\u001b[0m in \u001b[0;36mvalidate_gate\u001b[0;34m(self, gate)\u001b[0m\n\u001b[1;32m    123\u001b[0m                                  \u001b[0mops\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mZPowGate\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    124\u001b[0m                                  ops.IdentityGate)):\n\u001b[0;32m--> 125\u001b[0;31m             \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'Unsupported gate: {!r}'\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mformat\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mgate\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    126\u001b[0m         if isinstance(gate, (ops.CNotPowGate,\n\u001b[1;32m    127\u001b[0m                              \u001b[0mops\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mCZPowGate\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;31mValueError\u001b[0m: Unsupported gate: cirq.H"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "7QvsNStFtXll",
        "colab_type": "text"
      },
      "source": [
        "###Constructor\n",
        "\n",
        "Let's take a look at the constructor for the NeutralAtomDevice class. There are a number of arguments needed to fully parametarize a device. The specific values for these numbers are expected improve over time for any physical device. Instead of constraining ourselves to how the device(s) look at a specific moment in time, the user is allowed to free or constrain themselves as  they see fit.\n",
        "\n",
        "---\n",
        "\n",
        "Gate duration variables: Depending on the specific implementation of the quantum gate, there may be a different amount of time needed to perform various actions. These arguments accept Duration and timedelta objects.\n",
        "\n",
        "*   measurement_duration: How long it takes for the device to measure a qubit\n",
        "\n",
        "*   gate_duration: The maximum amount of time it takes to execute a quantum gate\n",
        "\n",
        "---\n",
        "\n",
        "Parallelism limitations: Neutral atom devices implement quantum gates in one of two ways. One method is by hitting the entire qubit array with microwaves to simultaneously act on every qubit. This method implements global XY gates which take up to 100 microseconds to perform. Alternatively, we can shine laser light on some fraction of the array. Gates of this type typically take around 1 microsecond to perform. This method can act on one or more qubits at a time up to some limit dictated by the available laser power and the beam steering system used to address the qubits. Each category in the native gate set has its own limit.\n",
        "\n",
        "\n",
        "*   max_parallel_z: The maximum number of single qubit Z-axis rotations that can be applied in parallel\n",
        "\n",
        "*   max_parallel_xy: The maximum number of single qubit XY rotations that can be applied in parallel\n",
        "\n",
        "*   max_parallel_c: The maximum number of atoms that can be affected by controlled gates simulataneously\n",
        "\n",
        "Z-axis rotations and XY rotations use different light, so they have independent constraints. However, controlled gates make use of the light used to perform single qubit rotations in addition to extra laser frequencies. As such, the max_parallel_c argument is bounded above by the lesser of max_parallel_z and max_parallel_xy. \n",
        "\n",
        "---\n",
        "\n",
        "Other variables:\n",
        "\n",
        "*   qubits: A list of the qubits on the device. The only supported qubit type is GridQubit.\n",
        "\n",
        "*   control_radius: Every pair of atoms acted on by a controlled gate must be within this maximum distance of eachother for the gate to succeed. The distance is between qubits is measured by using their row and column values as coordinates.\n",
        "\n",
        "\n",
        "---\n",
        "\n",
        "The example device below has the following properties:\n",
        "\n",
        "*   The device is a 3x3 grid of qubits\n",
        "*   Measurements take 5ms\n",
        "*   Gates may take as long as 100us if we utilize global microwave gates. Otherwise, a more reasonable bound would be 1us.\n",
        "*   Controlled gates have next-nearest neighbor connectivity (control_radius of 2)\n",
        "*   A maximum of 3 qubits may be simultaneously acted on by any gate category \n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "PPYYsBZr2UTD",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "ms = cirq.Duration(nanos=10**6)\n",
        "us = cirq.Duration(nanos=10**3)\n",
        "neutral_device = cirq.NeutralAtomDevice(measurement_duration = 5*ms,\n",
        "                                       gate_duration = 100*us,\n",
        "                                       control_radius = 2,\n",
        "                                       max_parallel_z = 3,\n",
        "                                       max_parallel_xy = 3,\n",
        "                                       max_parallel_c = 3,\n",
        "                                       qubits = [cirq.GridQubit(row, col) \n",
        "                                                 for col in range(3) \n",
        "                                                 for row in range(3)])"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Ug-2oBPPtZzU",
        "colab_type": "text"
      },
      "source": [
        "###Moment/Circuit Rules\n",
        "\n",
        "Now that we know how to parametarize a NeutralAtomDevice, we can discuss some examples of valid and invalid moments and circuits. Each operation in a moment is treated as if they are performed simultaneously. This leaves us with a few constraints we need to abide by.\n",
        "\n",
        "\n",
        "1.   We need to respect the maximum number of parallel gates for any gate type as discussed above\n",
        "2.   All instances of gates in the same category in the same moment must be identical\n",
        "3.   Since controlled gates make use of all types of light used to make gates, controlled gates cannot be applied in parallel with other gate types\n",
        "4.   Qubits acted on by different controlled gates in parallel must be farther apart than control_radius so that the entanglement mechanism doesn't cause the gates to interfere with one another\n",
        "5.   Measurements must be terminal\n",
        "\n",
        "\n",
        "\n",
        "---\n",
        "\n",
        "Some examples of valid moments are given below. We know the moments we constructed were valid because the circuit allowed us to add them knowing that they needed to pass the neutral_device validation methods."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "Nr-rfUgOtDxE",
        "colab_type": "code",
        "outputId": "020b86fa-2aed-4692-98ce-586eb69516ea",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 211
        }
      },
      "source": [
        "# Moment/Circuit Examples\n",
        "moment_circ = cirq.Circuit(device=neutral_device)\n",
        "qubits = [cirq.GridQubit(row, col) for col in range(3) for row in range(3)]\n",
        "\n",
        "# Three qubits affected by a Z gate in parallel with Three qubits affected\n",
        "# by an XY gate\n",
        "operation_list_one = cirq.Z.on_each(*qubits[:3])+cirq.X.on_each(*qubits[3:6])\n",
        "valid_moment_one = cirq.Moment(operation_list_one)\n",
        "moment_circ.append(valid_moment_one)\n",
        "\n",
        "# A TOFFOLI gate on three qubits that are close enough to eachother\n",
        "operation_list_two = [cirq.TOFFOLI.on(*qubits[:3])]\n",
        "valid_moment_two = cirq.Moment(operation_list_two)\n",
        "moment_circ.append(valid_moment_two)\n",
        "\n",
        "\n",
        "print(moment_circ)"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "(0, 0): ───Z───@───\n",
            "               │\n",
            "(0, 1): ───X───┼───\n",
            "               │\n",
            "(1, 0): ───Z───@───\n",
            "               │\n",
            "(1, 1): ───X───┼───\n",
            "               │\n",
            "(2, 0): ───Z───X───\n",
            "\n",
            "(2, 1): ───X───────\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "l6jE7NnKtjQU",
        "colab_type": "text"
      },
      "source": [
        "Frequently, you aren't explicitly constructing moments and adding them into circuits. You may more frequently find  yourself directly appending a list of operations into the circuit. Let's look at the result if we attempt this method with a global operation."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "u8oA9R5aCbEP",
        "colab_type": "code",
        "outputId": "88bae769-2f21-43fb-aa8d-805b8e780be9",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 302
        }
      },
      "source": [
        "global_circuit = cirq.Circuit(device=neutral_device)\n",
        "global_list_of_operations = cirq.X.on_each(*qubits)\n",
        "global_circuit.append(global_list_of_operations)\n",
        "print(global_circuit)"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "(0, 0): ───X───────────\n",
            "\n",
            "(0, 1): ───────X───────\n",
            "\n",
            "(0, 2): ───────────X───\n",
            "\n",
            "(1, 0): ───X───────────\n",
            "\n",
            "(1, 1): ───────X───────\n",
            "\n",
            "(1, 2): ───────────X───\n",
            "\n",
            "(2, 0): ───X───────────\n",
            "\n",
            "(2, 1): ───────X───────\n",
            "\n",
            "(2, 2): ───────────X───\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ZPd3emooFqa5",
        "colab_type": "text"
      },
      "source": [
        "That doesn't look right! It looks like the insertion method tried to place the gates in one at a time and decided it needed three moments to satisfy the request. There are two ways of getting around this in Cirq. One is to manually construct the moment as above."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "FxmKkfCEF744",
        "colab_type": "code",
        "outputId": "7c87f248-4672-419e-bb4c-22fd86df3b2d",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 316
        }
      },
      "source": [
        "global_moment_circuit = cirq.Circuit(device=neutral_device)\n",
        "global_moment = cirq.Moment(cirq.X.on_each(*qubits))\n",
        "global_moment_circuit.append(global_moment)\n",
        "print(global_moment_circuit)"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "(0, 0): ───X───\n",
            "\n",
            "(0, 1): ───X───\n",
            "\n",
            "(0, 2): ───X───\n",
            "\n",
            "(1, 0): ───X───\n",
            "\n",
            "(1, 1): ───X───\n",
            "\n",
            "(1, 2): ───X───\n",
            "\n",
            "(2, 0): ───X───\n",
            "\n",
            "(2, 1): ───X───\n",
            "\n",
            "(2, 2): ───X───\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "3E-tqsmlGKjD",
        "colab_type": "text"
      },
      "source": [
        "Another way to achieve this task is the ParallelGateOperation class. Most Operation objects correspond to a single gate acting on some qubits. The ParallelGateOperation class corresponds to multiple copies of a single gate acting on some qubits in parallel. Since it is a single operation, the default insertion methods won't break it up into multiple moments when adding it into the circuit!"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "OIZux5rFGrLs",
        "colab_type": "code",
        "outputId": "161e947a-d97f-4c09-ea08-42fa4fd0cb8e",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 302
        }
      },
      "source": [
        "parallel_gate_op_circuit = cirq.Circuit(device=neutral_device)\n",
        "parallel_gate_op = cirq.ParallelGateOperation(cirq.X,qubits)\n",
        "parallel_gate_op_circuit.append(parallel_gate_op)\n",
        "print(parallel_gate_op_circuit)"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "(0, 0): ───X───\n",
            "\n",
            "(0, 1): ───X───\n",
            "\n",
            "(0, 2): ───X───\n",
            "\n",
            "(1, 0): ───X───\n",
            "\n",
            "(1, 1): ───X───\n",
            "\n",
            "(1, 2): ───X───\n",
            "\n",
            "(2, 0): ───X───\n",
            "\n",
            "(2, 1): ───X───\n",
            "\n",
            "(2, 2): ───X───\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "1byvHcWvHx-D",
        "colab_type": "text"
      },
      "source": [
        "###Grover's Algorithm\n",
        "Now that we have the details out of the way, we can take a look at what implementing a real quantum algorithm might look like on a NeutralAtomDevice. Since the current limit on having multiple controls on a gate is two, lets look at the three qubit Grover search. For this problem, there is some special target state out of the $N = 2^n$ possible basis states that we'd like to identify. We have access to a quantum oracle that applies a phase to this state relative to every other basis state. The algorithm succeeds if we measure the desired state when we make a measurement on all the qubits after the circuit is run.\n",
        "\n",
        "\n",
        "---\n",
        "\n",
        "Classically, this corresponds to an unordered database search with a database of size $N=2^n$. On average, it will take $N/2$ applications of a classical oracle to find the desired state in the database. With Grover's algorithm, it is possible to succeed with high probability in $O(\\sqrt N)$ applications of the quantum oracle.\n",
        "\n",
        "\n",
        "---\n",
        "\n",
        "Grover's algorithm works by initially preparing the quantum state\n",
        "$$|s\\rangle = \\frac{1}{\\sqrt{N}}\\sum_{x=0}^{N-1}{|x\\rangle}_.$$\n",
        "\n",
        "This is an even superposition of each state in the computational basis and can be obtained by applying a Hadamard gate or a $Y^{1/2}$ gate on a register with each qubit initialized to $|0\\rangle$. After this initial state is prepared, Grover's algorithm consists of applying the quantum oracle followed by a diffusion operator. \n",
        "\n",
        "The quantum oracle places a relative phase on the target state we want to measure and the diffusion operator utilizes that phase difference to amplify the probability of measuring the target state relative to other states in the computational basis.\n",
        "The diffusion operator is given by $U_s = 2 |s\\rangle \\langle s| - I.$\n",
        "\n",
        "\n",
        "---\n",
        "\n",
        "\n",
        "We can calculate the probability of success as a function of the number of repititions R that we apply the oracle and diffusion operator. The result is $$P_{success} = \\sin^2 ((2R+1)\\arcsin(\\frac{1}{\\sqrt{N}})_,$$\n",
        "with the maximum probability of success will occur when $R \\approx \\pi \\sqrt{N}/4.$ \n",
        "\n",
        "\n",
        "---\n",
        "\n",
        "We know what these operators look like in Dirac notation, but now we have to compile them into the language of quantum gates. We'll start with the oracle. We can construct the oracle out of controlled-Z gates and NOT (X) gates. A Controlled-Z gate applies a $\\pi$ phase shift to the state where each qubit is in the $|1 \\rangle $ state. We can select a different state to recieve the phase shift by sandwiching the controlled-Z gate with X gates on any of the qubits whose desired measurement outcome is $|0 \\rangle$. We can implement a generator for the oracle operator with the below code in Cirq."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "uQ50bqZKZXVf",
        "colab_type": "code",
        "outputId": "d188de33-8918-4016-840e-b1f79278bf3c",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 105
        }
      },
      "source": [
        "def oracle(qubits, key_bits):\n",
        "    yield (cirq.X(q) for (q, bit) in zip(qubits, key_bits) if not bit)\n",
        "    yield cirq.CCZ(*qubits)\n",
        "    yield (cirq.X(q) for (q, bit) in zip(qubits, key_bits) if not bit)\n",
        "\n",
        "# Try changing the key to see the relationship between\n",
        "# the placement of the X gates and the key\n",
        "key = (1, 0, 1)\n",
        "qubits = [cirq.GridQubit(0,col) for col in range(3)]\n",
        "oracle_example_circuit = cirq.Circuit().from_ops(oracle(qubits,key))\n",
        "print(oracle_example_circuit)"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "(0, 0): ───────@───────\n",
            "               │\n",
            "(0, 1): ───X───@───X───\n",
            "               │\n",
            "(0, 2): ───────@───────\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "hOCGBzJ9dviO",
        "colab_type": "text"
      },
      "source": [
        "A quick Google search of how to implement the diffusion operator will provide us with the below implementation."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "63Y-GsLiH8Nm",
        "colab_type": "code",
        "outputId": "2415d9cd-c7e1-4107-c262-27be128405bc",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 105
        }
      },
      "source": [
        "def diffusion_operator(qubits):\n",
        "    yield cirq.H.on_each(*qubits)\n",
        "    yield cirq.X.on_each(*qubits)\n",
        "    yield cirq.CCZ(*qubits)\n",
        "    yield cirq.X.on_each(*qubits)\n",
        "    yield cirq.H.on_each(*qubits)\n",
        "    \n",
        "qubits = [cirq.GridQubit(0,col) for col in range(3)]\n",
        "diffusion_circuit = cirq.Circuit().from_ops(diffusion_operator(qubits))\n",
        "print(diffusion_circuit)"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "(0, 0): ───H───X───@───X───H───\n",
            "                   │\n",
            "(0, 1): ───H───X───@───X───H───\n",
            "                   │\n",
            "(0, 2): ───H───X───@───X───H───\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "yo4E2JSoe00x",
        "colab_type": "text"
      },
      "source": [
        "If we put it all together and note that for the three qubit case, the optimal number of applications of the oracle and diffusion operator is two, we get the below circuit."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "TSfFAmk2e_Q8",
        "colab_type": "code",
        "outputId": "2293ddf5-462d-4392-8807-6dc58e9eea0a",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 105
        }
      },
      "source": [
        "def initial_hadamards(qubits):\n",
        "    yield cirq.H.on_each(*qubits)\n",
        "\n",
        "uncompiled_circuit = cirq.Circuit()\n",
        "key = (1,0,1)\n",
        "qubits = [cirq.GridQubit(0,0),cirq.GridQubit(0,1),cirq.GridQubit(0,2)]\n",
        "uncompiled_circuit.append(initial_hadamards(qubits))\n",
        "uncompiled_circuit.append(oracle(qubits,key))\n",
        "uncompiled_circuit.append(diffusion_operator(qubits))\n",
        "uncompiled_circuit.append(oracle(qubits,key))\n",
        "uncompiled_circuit.append(diffusion_operator(qubits))\n",
        "print(uncompiled_circuit)"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "(0, 0): ───H───────@───H───X───────@───X───H───────@───H───X───────@───X───H───\n",
            "                   │               │               │               │\n",
            "(0, 1): ───H───X───@───X───H───X───@───X───H───X───@───X───H───X───@───X───H───\n",
            "                   │               │               │               │\n",
            "(0, 2): ───H───────@───H───X───────@───X───H───────@───H───X───────@───X───H───\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "iTmPFGsahCh-",
        "colab_type": "text"
      },
      "source": [
        "This circuit does implement Grover's algorithm, but it doesn't work for our NeutralAtomDevice class because of the Hadamard gates. The Hadamard gates show up in the Diffusion Operator steps and the initial \"Hadamard Everything\" step. We can simplify the Diffusion Operator definition and the initial Hadamard step by decomposing the Hadamard gate into products of XY gates.\n",
        "\n",
        "\n",
        "*   $H=X Y^{1/2}$ \n",
        "*   $H=Y^{-1/2} X$\n",
        "*  $H=Y^{1/2}Z$\n",
        "\n",
        "Using these two rules, we can instead make a neutral atom comptable version of the circuit given below."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "HsjMeVNkie2b",
        "colab_type": "code",
        "outputId": "ebc7b261-df8e-491a-c71a-0e39632851cf",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 105
        }
      },
      "source": [
        "def neutral_atom_initial_step(qubits):\n",
        "    yield cirq.ParallelGateOperation(cirq.Y**(1/2), qubits)\n",
        "    \n",
        "def neutral_atom_diffusion_operator(qubits):\n",
        "    yield cirq.ParallelGateOperation(cirq.Y**(1/2), qubits)\n",
        "    yield cirq.CCZ(*qubits)\n",
        "    yield cirq.ParallelGateOperation(cirq.Y**(-1/2), qubits)\n",
        "\n",
        "    \n",
        "ms = cirq.Duration(nanos=10**6)\n",
        "us = cirq.Duration(nanos=10**3)\n",
        "qubits = [cirq.GridQubit(row, col) for col in range(3) for row in range(1)]\n",
        "three_qubit_device = cirq.NeutralAtomDevice(measurement_duration = 5*ms,\n",
        "                                           gate_duration = us,\n",
        "                                           control_radius = 2,\n",
        "                                           max_parallel_z = 3,\n",
        "                                           max_parallel_xy = 3,\n",
        "                                           max_parallel_c = 3,\n",
        "                                           qubits=qubits)\n",
        "key = (0,1,0)\n",
        "compiled_grover_circuit = cirq.Circuit(device=three_qubit_device)\n",
        "compiled_grover_circuit.append(neutral_atom_initial_step(qubits))\n",
        "compiled_grover_circuit.append(oracle(qubits,key))\n",
        "compiled_grover_circuit.append(neutral_atom_diffusion_operator(qubits))\n",
        "compiled_grover_circuit.append(oracle(qubits,key))\n",
        "compiled_grover_circuit.append(neutral_atom_diffusion_operator(qubits))\n",
        "print(compiled_grover_circuit)"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "(0, 0): ───Y^0.5───X───@───X───Y^0.5───@───Y^-0.5───X───@───X───Y^0.5───@───Y^-0.5───\n",
            "                       │               │                │               │\n",
            "(0, 1): ───Y^0.5───────@───────Y^0.5───@───Y^-0.5───────@───────Y^0.5───@───Y^-0.5───\n",
            "                       │               │                │               │\n",
            "(0, 2): ───Y^0.5───X───@───X───Y^0.5───@───Y^-0.5───X───@───X───Y^0.5───@───Y^-0.5───\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "zBfHYu7lfwbY",
        "colab_type": "text"
      },
      "source": [
        "Let's quickly verify that this implementation of the algorithm on our device actually works by altering the number of times we apply the oracle and diffusion operators. We would expect to reproduce the analytical result given above."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "MUC33tMYgJQV",
        "colab_type": "code",
        "outputId": "572d7c09-7c55-41de-e2b9-8cdf58fc8a9a",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 295
        }
      },
      "source": [
        "def grover_circuit_with_n_repetitions(n, key):\n",
        "    ms = cirq.Duration(nanos=10**6)\n",
        "    us = cirq.Duration(nanos=10**3)\n",
        "    qubits = [cirq.GridQubit(row, col) for col in range(3) for row in range(1)]\n",
        "    three_qubit_device = cirq.NeutralAtomDevice(measurement_duration = 5*ms,\n",
        "                                               gate_duration = us,\n",
        "                                               control_radius = 2,\n",
        "                                               max_parallel_z = 3,\n",
        "                                               max_parallel_xy = 3,\n",
        "                                               max_parallel_c = 3,\n",
        "                                               qubits=qubits)\n",
        "    grover_circuit = cirq.Circuit(device=three_qubit_device)\n",
        "    grover_circuit.append(neutral_atom_initial_step(qubits))\n",
        "    for repetition in range(n):\n",
        "      grover_circuit.append(oracle(qubits,key))\n",
        "      grover_circuit.append(neutral_atom_diffusion_operator(qubits))\n",
        "      \n",
        "    return grover_circuit\n",
        "      \n",
        "success_probabilities = []\n",
        "key = (0,1,1)\n",
        "N = 2**3\n",
        "#Convert key from binary to a base 10 number\n",
        "diag = sum(2**(2-count) for (count, val) in enumerate(key) if val)\n",
        "num_points = 10\n",
        "for repetitions in range(num_points):\n",
        "    test_circuit = grover_circuit_with_n_repetitions(repetitions, key)\n",
        "    sim = cirq.Simulator()\n",
        "    result = sim.simulate(test_circuit)\n",
        "    rho = result.density_matrix_of(qubits)\n",
        "    success_probabilities.append(np.real(rho[diag][diag]))\n",
        "\n",
        "plt.scatter(range(num_points), success_probabilities, label=\"Simulation\")\n",
        "x = np.linspace(0, num_points, 1000)\n",
        "y = np.sin((2*x+1)*np.arcsin(1/np.sqrt(N)))**2\n",
        "plt.plot(x, y, label=\"Theoretical Curve\")\n",
        "plt.title(\"Probability of Success Vs. Number of Oracle-Diffusion Operators\")\n",
        "plt.ylabel(\"Probability of Success\")\n",
        "plt.xlabel(\"Number of Times Oracle and Diffusion Operators are Applied\")\n",
        "plt.legend(loc='upper right')\n",
        "plt.show()"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "display_data",
          "data": {
            "image/png": "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\n8XhC5/8DhXZ5N+FY/XQAAAAASUVORK5CYII=\n",
            "text/plain": [
              "<Figure size 432x288 with 1 Axes>"
            ]
          },
          "metadata": {
            "tags": []
          }
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "oSPDCZPCmugO",
        "colab_type": "text"
      },
      "source": [
        "The results match! And we actually see that if we can afford to increase the number of times we apply the oracle and diffusion operators to six, we can get an improved probability of success."
      ]
    }
  ]
}